#include <SaveTinyXml2.h>
#include <base/Intent.h>
#include <log/log_err.h>
#include <kernel/tinyxml2/tinyxml2.h>

using namespace tinyxml2;

static const char *INTER = "inter";
static const char *DOUBLE = "double";
static const char *STRING = "string";
static const char *BOOLEAN = "boolen";

SaveTinyXml2::SaveTinyXml2(/* args */)
{

}

SaveTinyXml2::~SaveTinyXml2()
{

}

/* 将Intent保存在filename中 */
bool SaveTinyXml2::saveIntent(const char* filename, const Intent& intent)
{
    char str[128] = {0};
    bool ret = false;
    std::string key;
    std::string stringValue;
    int interValue = 0;
    double doubleValue = 0;
    bool boolValue = true;
    XMLError errorId;
    XMLDocument *doc            = nullptr;
    XMLPrinter  *printer        = nullptr;
    XMLElement  *root           = nullptr;
    XMLElement  *arrayInter     = nullptr;
    XMLElement  *arrayDouble    = nullptr;
    XMLElement  *arrayString    = nullptr;
    XMLElement  *arrayBool      = nullptr;
    XMLElement  *item           = nullptr;

    SIGNWAY_ERROR_GOTO(filename == nullptr, RETURN, "filename is null");
    
    doc = new XMLDocument();
    printer = new XMLPrinter();
    
    root           = doc->NewElement("root");
    arrayInter     = doc->NewElement(INTER);
    arrayDouble    = doc->NewElement(DOUBLE);
    arrayString    = doc->NewElement(STRING);
    arrayBool      = doc->NewElement(BOOLEAN);

    doc->InsertEndChild(root);
    root->InsertEndChild(arrayInter);
    root->InsertEndChild(arrayDouble);
    root->InsertEndChild(arrayString);
    root->InsertEndChild(arrayBool);

    for(auto value : intent.m_extra_i) {
        item = doc->NewElement(value.first.c_str());
        memset(str, 0, sizeof(str));
        snprintf(str, sizeof(str), "%d", value.second);
        item->InsertNewText(str);
        arrayInter->InsertEndChild(item);
    }

    for (auto value : intent.m_extra_d) {
        item = doc->NewElement(value.first.c_str());
        memset(str, 0, sizeof(str));
        snprintf(str, sizeof(str), "%.2f", value.second);
        item->InsertNewText(str);
        arrayDouble->InsertEndChild(item);
    }

    for (auto value : intent.m_extra_s) {
        item = doc->NewElement(value.first.c_str());
        memset(str, 0, sizeof(str));
        snprintf(str, sizeof(str), "%s", value.second.c_str());
        item->InsertNewText(str);
        arrayString->InsertEndChild(item);
    }

    for (auto value : intent.m_extra_b) {
        item = doc->NewElement(value.first.c_str());
        memset(str, 0, sizeof(str));
        if (value.second) {
            snprintf(str, sizeof(str), "true");
        } else {
            snprintf(str, sizeof(str), "false");
        }
        item->InsertNewText(str);
        arrayBool->InsertEndChild(item);
    }

    doc->Print(printer);
    SIGNWAY_LOGI("\n%s", printer->CStr());

    doc->SaveFile(filename);
    errorId = doc->ErrorID();
    SIGNWAY_ERROR_GOTO(errorId > 0, RETURN, 
            "%s file load failed, error: %d", filename, errorId);

    ret = true;

RETURN:
    if (doc != nullptr) {
        delete doc;doc = nullptr;
    }
    if (printer != nullptr) {
        delete printer;printer = nullptr;
    }
    return ret;
}

/* filename文件内容转Intent */
bool SaveTinyXml2::loadIntent(const char* filename, Intent& intent)
{
    bool ret = false;
    std::string key;
    int interValue = 0;
    double doubleValue = 0;
    bool boolValue = true;
    const char *stringValue = nullptr;
    XMLError errorId;
    XMLDocument *doc            = nullptr;
    XMLElement  *root           = nullptr;
    XMLElement  *arrayInter     = nullptr;
    XMLElement  *arrayDouble    = nullptr;
    XMLElement  *arrayString    = nullptr;
    XMLElement  *arrayBool      = nullptr;
    XMLElement  *item           = nullptr;
    XMLPrinter  *printer        = nullptr;

    SIGNWAY_ERROR_GOTO(filename == nullptr, RETURN, "filename is null");

    doc = new XMLDocument();
    printer = new XMLPrinter();
    doc->LoadFile(filename);
    errorId = doc->ErrorID();
    SIGNWAY_ERROR_GOTO(errorId > 0, RETURN, 
            "%s file load failed, error: %d", filename, errorId);
    doc->Print(printer);
    SIGNWAY_LOGI("\n%s", printer->CStr());

    root = doc->RootElement();
    SIGNWAY_ERROR_GOTO(root == nullptr, RETURN, "root is null");

    arrayInter = root->FirstChildElement(INTER);
    SIGNWAY_ERROR_GOTO(arrayInter == nullptr, RETURN, "arrayInter is null");

    item = arrayInter->FirstChildElement();
    while (item) {
        key = item->Name();
        interValue = 0;

        errorId = item->QueryIntText(&interValue);
        item = item->NextSiblingElement();

        SIGNWAY_ERROR_CONTINUE(errorId > 0, "%s not found!\r\n", key.c_str());
        SIGNWAY_LOGI("key: %s, value: %d", key.c_str(), interValue);

        intent.putExtra(key, interValue);
    }

    arrayDouble = root->FirstChildElement(DOUBLE);
    SIGNWAY_ERROR_GOTO(arrayDouble == nullptr, RETURN, "arrayDouble is null");

    item = arrayDouble->FirstChildElement();
    while (item) {
        key = item->Name();
        doubleValue = 0;

        errorId = item->QueryDoubleText(&doubleValue);
        item = item->NextSiblingElement();

        SIGNWAY_ERROR_CONTINUE(errorId > 0, "%s not found!\r\n", key.c_str());
        SIGNWAY_LOGI("key: %s, value: %.2f", key.c_str(), doubleValue);

        intent.putExtra(key, doubleValue);
    }

    arrayString = root->FirstChildElement(STRING);
    SIGNWAY_ERROR_GOTO(arrayString == nullptr, RETURN, "arrayString is null");

    item = arrayString->FirstChildElement();
    while (item) {
        key = item->Name();

        stringValue = item->GetText();
        item = item->NextSiblingElement();

        SIGNWAY_ERROR_CONTINUE(stringValue == nullptr, "%s not found!\r\n", key.c_str());
        SIGNWAY_LOGI("key: %s, value: %s", key.c_str(), stringValue);

        intent.putExtra(key, std::string(stringValue));
    }

    arrayBool = root->FirstChildElement(BOOLEAN);
    SIGNWAY_ERROR_GOTO(arrayBool == nullptr, RETURN, "arrayBool is null");

    item = arrayBool->FirstChildElement();
    while (item) {
        key = item->Name();

        errorId = item->QueryBoolText(&boolValue);
        item = item->NextSiblingElement();

        SIGNWAY_ERROR_CONTINUE(errorId > 0, "%s not found!\r\n", key.c_str());
        SIGNWAY_LOGI("key: %s, value: %d", key.c_str(), boolValue);

        intent.putExtra(key, boolValue);
    }
    ret = true;

RETURN:
    if (doc != nullptr) {
        delete doc;doc = nullptr;
    }
    if (printer != nullptr) {
        delete printer;printer = nullptr;
    }
    return ret;
}
